package com.uinnova.product.eam.base.web.feign;

import com.alibaba.fastjson.JSON;
import com.uinnova.product.eam.base.web.http.response.CustomHttpServletResponseWrapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.io.InputStreamSource;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * 
 * @author zhaoyujie
 *
 */
@Aspect
@Slf4j
public class FeignServerControllerLogAspect {

    /**
     * 与前端约定的请求唯一标识字段
     */
    private String requestIdHeaderName = "requestId";

    /**
     * feign接口的请求标识
     */
    private String feignReaquestIdHeaderName = "feignRequestId";

    /**
     * 消费者透传来的请求唯一标识
     */
    private String sourceReaquestIdHeaderName = "sourceRequestId";
    {
        log.info("请求日志切面注册web");
    }

    @Pointcut("execution(* com.uinnova.product.eam.*.controller..*(..))")
    public void feignServer() {
    }

    @Around("feignServer()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Date startTime = new Date();
        // 获取代理地址、请求地址、请求类名、方法名
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = sra.getRequest();
        String ip = getIpAddress(request);
        String uri = request.getRequestURI();
        String clsName = proceedingJoinPoint.getTarget().getClass().getSimpleName();
        String methodName = proceedingJoinPoint.getSignature().getName();
        String requestId = request.getHeader(requestIdHeaderName);
        String feignRequestId = request.getHeader(feignReaquestIdHeaderName);
        String sourceRequestId = request.getHeader(sourceReaquestIdHeaderName);
        log.info("接收到来自【{}】请求，uri为【{}】,请求标识为【{}】,feign标识为【{}】，透传标识为【{}】", ip, uri, requestId, feignRequestId,
                sourceRequestId);
        log.debug("路由到类【{}】方法【{}】", clsName, methodName);
        CustomHttpServletResponseWrapper response = null;
        try {
            // 获取方法参数
            MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
            String[] paramNames = methodSignature.getParameterNames();
            Object[] paramVals = proceedingJoinPoint.getArgs();
            if (paramNames != null && paramNames.length > 0) {
                for (int index = 0; index < paramNames.length; index++) {
                    String paramName = paramNames[index];
                    Object paramVal = paramVals[index];
                    if (paramVal instanceof HttpServletRequest) {
                        continue;
                    } else if (paramVal instanceof HttpServletResponse) {
                        try {
                            response = (CustomHttpServletResponseWrapper) paramVal;
                        } catch (Exception e) {
                            log.error("获取请求自定义response失败，可能由于未注册自定义CustomHttpServletResponseWrapper或正确配置请求拦截");
                        }
                        continue;
                    } else if (paramVal instanceof InputStreamSource) {
                        continue;
                    } else {
                        log.info("参数【{}】为【{}】", paramName, JSON.toJSONString(paramVal));
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取参数异常", e);
        }
        Object result = null;
        result = proceedingJoinPoint.proceed();
        try {
            Date endTime = new Date();
            log.info("本次请求共处理【{}】毫秒", (endTime.getTime() - startTime.getTime()));
            if (response != null && response.getBody() != null) {
                log.debug("返回消息为【{}】", new String(response.getBody()));
            }
            if (result != null) {
                log.debug("返回消息为【{}】", JSON.toJSONString(result));
            }
        } catch (Exception e) {
        }
        return result;
    }

    /**
     * 获取请求ip
     * 
     * @param request
     * @return
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
